package com.stox.client.ui.javafx.core.event.listener;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

import com.stox.client.api.core.WebSocketClient;
import com.stox.shared.core.model.Bar;
import com.stox.shared.core.model.intf.Callback;
import com.stox.shared.core.util.converter.BarConverter;


public class BarChangeListenerRegistry implements Callback<String,Boolean>{
	
	public static final BarChangeListenerRegistry INSTANCE = new BarChangeListenerRegistry();
	
	private final Map<Long, Set<String>> registry = new HashMap<>();
	private final Map<Long,SimpleObjectProperty<Bar>> cache = new HashMap<>();
	
	private BarChangeListenerRegistry() {	
		WebSocketClient.INSTANCE.addCallback(this);
	}
	
	/**
	 * Caller subscribes to bar values of a scrip.
	 * 
	 * @param key
	 * @param scrip
	 * @return
	 */
	public ReadOnlyObjectProperty<Bar> subscribe(String key, Long scripId){
		SimpleObjectProperty<Bar> property = cache.get(scripId);
		Set<String> registrations = registry.get(scripId);
		if(null == property){
			property = new SimpleObjectProperty<Bar>();
			cache.put(scripId, property);
			registrations = new HashSet<>();
			registry.put(scripId, registrations);
			subscribe(scripId);
		}
		registrations.add(key);
		return property;
	}
	
	/**
	 * Caller unsubscribes from bar values from a scrip.
	 * 
	 * @param key
	 * @param scrip
	 */
	public void unsubscribe(String key, Long scripId){
		Set<String> registrations = registry.get(scripId);
		if(null != registrations){
			registrations.remove(key);
			if(registrations.isEmpty()){
				cache.remove(scripId);
				unsubscribe(scripId);
			}
		}
	}
	
	/**
	 * Caller unsubscribes from the bar values of all scrips
	 * @param key
	 */
	public void unsubscribe(String key){
		for(Long scripId : registry.keySet()){
			unsubscribe(key, scripId);
		}
	}
	
	@Override
	public Boolean execute(String message) {
		if(BarConverter.INSTANCE.supports(message)){
			Bar bar = BarConverter.INSTANCE.decode(message);
			SimpleObjectProperty<Bar> barProperty = cache.get(bar.getScripId());
			if(null == barProperty){
				unsubscribe(bar.getScripId());
			}else{
				barProperty.set(bar);
			}
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}
	
	private void subscribe(Long scripId){
		WebSocketClient.INSTANCE.sendMessage(BarConverter.INSTANCE.getId()+","+scripId+","+Boolean.TRUE);
	}
	
	private void unsubscribe(Long scripId){
		WebSocketClient.INSTANCE.sendMessage(BarConverter.INSTANCE.getId()+","+scripId+","+Boolean.FALSE);
	}
	
}

